{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b30fae8e",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Using Active Learning in a 3D Similarity Search \n",
    "In this tutorial we'll consider a full example where we use active learning to find molecules with shape and pharmcophoric features similar to a query molecule. The code here is very similar to the code in active_regression.ipynb.  The only substantial change is in the oracle which scores the molecules. Some of the code and data in this notebook was borrowed from other open source projects. \n",
    "- The query and database molecules were taken from the [LitPCBA](https://pubs.acs.org/doi/10.1021/acs.jcim.0c00155) set. \n",
    "- The 3D overlay code came from [ESPSim](https://github.com/hesther/espsim)\n",
    "- Some code was also borrowed from [Lig3DLens](https://github.com/healx/lig3dlens)  \n",
    "\n",
    "Many thanks to the authors of these packages for their commitment to open science. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14785c51",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Install the necessary Python packages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e7c3d153",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-05T22:01:07.528407Z",
     "start_time": "2025-05-05T22:01:07.526021Z"
    },
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "%%capture\n",
    "import sys\n",
    "IN_COLAB = 'google.colab' in sys.modules\n",
    "if IN_COLAB:\n",
    "    !pip install 'modAL-python>=0.4.1'\n",
    "    !pip install useful-rdkit-utils\n",
    "    !pip install git+https://github.com/hesther/espsim.git@533a53105858d1a25cbe2fb54dd7208d7989caa1\n",
    "    !pip install loguru\n",
    "    !pip install py3Dmol"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a053bf9",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "If we're running on Google Colab, we need to copy the data files and a couple of Python files"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "07f45e68",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-05T22:01:28.909269Z",
     "start_time": "2025-05-05T22:01:28.906255Z"
    },
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import sys\n",
    "if IN_COLAB:\n",
    "  import urllib.request\n",
    "\n",
    "  url = \"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/active_learning/align3D_score.py\"\n",
    "  filename = \"align3D_score.py\"\n",
    "  urllib.request.urlretrieve(url,filename)\n",
    "  url = \"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/active_learning/gen_conformers.py\"\n",
    "  filename = \"gen_conformers.py\"\n",
    "  urllib.request.urlretrieve(url,filename)\n",
    "\n",
    "  os.makedirs(\"./data\", exist_ok=True)\n",
    "  url = \"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/active_learning/data/2chw_lig.sdf\"\n",
    "  filename = \"data/2chw_lig.sdf\"\n",
    "  urllib.request.urlretrieve(url,filename)\n",
    "  url = \"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/active_learning/data/MAPK1.csv\"\n",
    "  filename = \"data/MAPK1.csv\"\n",
    "  urllib.request.urlretrieve(url,filename)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bb2eed3",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Import the the libraries we'll need. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "8debb6a8",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_10/lib/python3.11/site-packages/espsim/helpers.py:7: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.\n",
      "  import pkg_resources\n"
     ]
    }
   ],
   "source": [
    "from operator import itemgetter\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import sklearn.gaussian_process as gp\n",
    "import useful_rdkit_utils as uru\n",
    "from modAL.acquisition import BaseLearner\n",
    "from modAL.models import BayesianOptimizer\n",
    "from modAL.utils.data import modALinput\n",
    "from modAL.acquisition import optimizer_PI\n",
    "from rdkit import Chem\n",
    "from sklearn.gaussian_process import GaussianProcessRegressor\n",
    "from tqdm.auto import tqdm\n",
    "from align3D_score import score_alignment\n",
    "from gen_conformers import generate_conformers\n",
    "import py3Dmol"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3669d800",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Define an Oracle\n",
    "Here's where we define the oracle that overlays the molecules and compares the shapes and pharmacophoric features. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "5da4e59b",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "class ShapeOracle:\n",
    "    # instantiate the oracle with a query molecule\n",
    "    def __init__(self, ref_molfile):\n",
    "        self.ref_mol = Chem.MolFromMolFile(ref_molfile)\n",
    "        self.ref_mol = Chem.AddHs(self.ref_mol)\n",
    "\n",
    "    def get_values(self, input_smiles_list):\n",
    "        result_list = []\n",
    "        for smi in tqdm(input_smiles_list):\n",
    "            res = None\n",
    "            mol = Chem.MolFromSmiles(smi)\n",
    "            if mol:   \n",
    "                mol = Chem.AddHs(mol)\n",
    "                mol_3d = generate_conformers(mol,25)\n",
    "                if mol_3d:\n",
    "                    res = score_alignment(mol_3d,self.ref_mol)\n",
    "            result_list.append(res)\n",
    "        return result_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4cd0c12",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Define a Kernel Function for Gaussian Process Regression\n",
    "When we do active learning, we have to define a machine learning models that acts as a surrogate for the more expensive calculations.  In this case, we're going to use Gaussian Process Regression (GPR) to build our regression models.  To use GPR, we need to define a kernel function. Here we calculate a kernel based on the Tanimoto similarities of the molecules."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "8b37d306",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def calculate_similarity(a, b):\n",
    "    # Tanimoto similarity a vs. b\n",
    "    aa = np.sum(a, axis=1, keepdims=True)\n",
    "    bb = np.sum(b, axis=1, keepdims=True)\n",
    "    ab = np.matmul(a, b.T)\n",
    "    return np.true_divide(ab, aa + bb.T - ab)\n",
    "\n",
    "\n",
    "class TanimotoKernel(gp.kernels.NormalizedKernelMixin,\n",
    "                     gp.kernels.StationaryKernelMixin, gp.kernels.Kernel):\n",
    "\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    def __call__(self, X, Y=None, eval_gradient=False):\n",
    "        assert not eval_gradient\n",
    "        if Y is None:\n",
    "            Y = X\n",
    "        return calculate_similarity(X, Y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d15d603a",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Enable progress bars for the Pandas apply function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "41cfde32",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "tqdm.pandas()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4a13515",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Read the Input Data\n",
    "Read the input data.  This data comes from the [LitPBCBA](https://pubs.acs.org/doi/10.1021/acs.jcim.0c00155) sets. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "cd5060a1",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "df = pd.read_csv(\"data/MAPK1.csv\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e118c239",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Take a quick look at the data.  In this case we're going to ignore the activity column. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a8d6b48d",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>SMILES</th>\n",
       "      <th>Name</th>\n",
       "      <th>active</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>O=C(c1ccncc1)C23C[N@@]4C[N@@](C[NH+](C4)C2)C3</td>\n",
       "      <td>7975332</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>CCN(c1cccc(C)c1)S(=O)(=O)c2cccc3nsnc23</td>\n",
       "      <td>4241206</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>CC1CCCCN1c2nnc(N)s2</td>\n",
       "      <td>4243040</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>CN1C(=O)C2(C(=C([NH3+])Oc3[nH]nc(c4ccc(Cl)cc4)...</td>\n",
       "      <td>862502</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>CCOc1ccc(cc1OCC)C(=O)Nc2nnc(C)s2</td>\n",
       "      <td>7977049</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>62932</th>\n",
       "      <td>ClC1=CCC2C(C1)C(=O)N(CCC(=O)NCc3occc3)C2=O</td>\n",
       "      <td>4262792</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>62933</th>\n",
       "      <td>CCO\\C(=C/1\\C(c2ccc(OCC)c(OC)c2)n3nc(C)nc3N=C1C)\\O</td>\n",
       "      <td>7966068</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>62934</th>\n",
       "      <td>CCOC(=O)N1CC[NH+](CC(=O)c2c(C)[nH]c3ccccc23)CC1</td>\n",
       "      <td>4258998</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>62935</th>\n",
       "      <td>CC(C)(C)c1ccc(cc1)S(=O)(=O)N2CCN(CCC#N)CC2</td>\n",
       "      <td>7965720</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>62936</th>\n",
       "      <td>CCOC(=O)C1CCC[NH+](CC(=O)Nc2c(F)c(F)c(F)c(F)c2...</td>\n",
       "      <td>3714960</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>62937 rows × 3 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                  SMILES     Name  active\n",
       "0          O=C(c1ccncc1)C23C[N@@]4C[N@@](C[NH+](C4)C2)C3  7975332       0\n",
       "1                 CCN(c1cccc(C)c1)S(=O)(=O)c2cccc3nsnc23  4241206       0\n",
       "2                                    CC1CCCCN1c2nnc(N)s2  4243040       0\n",
       "3      CN1C(=O)C2(C(=C([NH3+])Oc3[nH]nc(c4ccc(Cl)cc4)...   862502       0\n",
       "4                       CCOc1ccc(cc1OCC)C(=O)Nc2nnc(C)s2  7977049       0\n",
       "...                                                  ...      ...     ...\n",
       "62932         ClC1=CCC2C(C1)C(=O)N(CCC(=O)NCc3occc3)C2=O  4262792       0\n",
       "62933  CCO\\C(=C/1\\C(c2ccc(OCC)c(OC)c2)n3nc(C)nc3N=C1C)\\O  7966068       0\n",
       "62934    CCOC(=O)N1CC[NH+](CC(=O)c2c(C)[nH]c3ccccc23)CC1  4258998       0\n",
       "62935         CC(C)(C)c1ccc(cc1)S(=O)(=O)N2CCN(CCC#N)CC2  7965720       0\n",
       "62936  CCOC(=O)C1CCC[NH+](CC(=O)Nc2c(F)c(F)c(F)c(F)c2...  3714960       0\n",
       "\n",
       "[62937 rows x 3 columns]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "798c4602",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Create a LigandId column, we'll use this when we determine how many of the top 100 molecules we've identified. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8c426477",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Generate Descriptors for the Machine Learning Model\n",
    "Add a fingerprint column to the dataframe."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "6b619510",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "08f485a169dd4bda9bf3e487564e05c3",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/62937 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "df['fp'] = df.SMILES.progress_apply(uru.smi2numpy_fp)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a7214e7",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Create a pool of fingerprints for the active learning algorithm to draw from."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "a907c5ea",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "X_pool = np.stack(df.fp.values)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7cfe40c",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Define a Few Utility Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30d4bd05",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "For the greedy search, we want to select the best scoring molecules, but we want to avoid selecting the same molecules multiple times. This function accepts a list of predictions and does the following.\n",
    "- Sort by score\n",
    "- Remove the molecules that were previously selected\n",
    "- Return the top **num_to_choose**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "fe11297b",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def find_best_idx(predicted, used, num_to_choose):\n",
    "    tmp_list = list(enumerate(predicted))\n",
    "    tmp_list.sort(key=itemgetter(1), reverse=True)\n",
    "    tmp_list = [x for x in tmp_list if x[0] not in used]\n",
    "    tmp_list = [x[0] for x in tmp_list]\n",
    "    return tmp_list[:num_to_choose]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76daee62",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "A function to combine the results from the shape search into the dataframe with the molecules. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "000ccbd0",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def compile_results(df_in, shape_results):\n",
    "    df_in['shape_res'] = shape_results\n",
    "    df_in.dropna(subset='shape_res',inplace=True)\n",
    "    df_in['score'] = [x.shape_score + x.esp_score + x.rdkit_score for x in df_in.shape_res]\n",
    "    return df_in"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1df581e",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Define the Acquisition Functions\n",
    "Here are a couple of acquistion functions.  The first **greedy** simply selects the **n** top scoring molecules to be evaluated by the oracle.  The second **my_max_PI** maximizes the Probability of Improvement (PI) and uses uncertainty and the scores to balance exploration and exploitation.  The git repo associated with our paper [\"Optimizing active learning for free energy calculations\"](https://www.sciencedirect.com/science/article/pii/S2667318522000204) has examples of several other acquistion functions.  TLDR from our work, the acquistion function doesn't make a huge difference. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "241046d8",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def greedy(optimizer: BaseLearner, X: modALinput, n_instances=1, used=[]):\n",
    "    res = optimizer.predict(X)\n",
    "    best_idx = find_best_idx(res, used, n_instances)\n",
    "    return best_idx, X[best_idx]\n",
    "\n",
    "def my_max_PI(optimizer: BaseLearner, X: modALinput, tradeoff: float = 0,\n",
    "           n_instances: int = 1, used = [], cycle = -1) -> np.ndarray:\n",
    "    pi = optimizer_PI(optimizer, X, tradeoff=tradeoff)\n",
    "    best_idx = find_best_idx(pi, used, n_instances)\n",
    "    return best_idx, X[best_idx]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d2e2253",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Run Active Learning"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73b52131",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Create an oracle that will return values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "aefb3804",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "oracle = ShapeOracle(\"data/2chw_lig.sdf\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf69645c",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "This is the main active learning loop. We'll do 5 cycles of active learning.  On Colab each loop takes 1-2 min, on my M1 Mac, each cycle takes 10-20 sec.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "575b177f",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4c80b142c6034f37b95f44f17bd977c9",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "64040a59489e49bb8c52a65284158d4f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_10/lib/python3.11/site-packages/sklearn/utils/deprecation.py:132: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e139b909dca8424abacc2154642375c8",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_10/lib/python3.11/site-packages/sklearn/utils/deprecation.py:132: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "79c285dbc59040a49e12e2001c1cfd2a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_10/lib/python3.11/site-packages/sklearn/utils/deprecation.py:132: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "82a33b8e9099456eb0dfe10665caf7b3",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_10/lib/python3.11/site-packages/sklearn/utils/deprecation.py:132: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "620873259cea4e1b9f17c6bfd4ab4b5e",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_10/lib/python3.11/site-packages/sklearn/utils/deprecation.py:132: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "# number of molecules to select at each active learning cycle\n",
    "n_instances = 100\n",
    "# number of active learning cycles to run\n",
    "n_cycles = 5\n",
    "\n",
    "# define the acquistion function\n",
    "query_strategy = my_max_PI\n",
    "\n",
    "# select an initial random sample\n",
    "sample_df = df.sample(n_instances).copy()\n",
    "sample_df['cycle'] = 0\n",
    "# get the shape scores for the random sample\n",
    "init_shape_res = oracle.get_values(sample_df.SMILES.values)\n",
    "# add the scores to the dataframe\n",
    "sample_df = compile_results(sample_df, init_shape_res)\n",
    "# define X and y to train the initial model\n",
    "X_initial = sample_df.fp.values\n",
    "y_initial = sample_df.score.values\n",
    "\n",
    "# instantiate the optimizer with an estimator, training data, and an acquistion function\n",
    "optimizer = BayesianOptimizer(estimator=GaussianProcessRegressor(kernel=TanimotoKernel()),\n",
    "                              X_training=np.stack(X_initial), y_training=y_initial,\n",
    "                              query_strategy=query_strategy)\n",
    "\n",
    "# initalize a list of results\n",
    "result_list = [sample_df]\n",
    "used = list(sample_df.index)\n",
    "\n",
    "# the active learning loop\n",
    "for i in range(0, n_cycles):\n",
    "    # ask the optimizer for the next set of molecules\n",
    "    query_idx, query_desc = optimizer.query(X_pool, n_instances=n_instances, used=used)\n",
    "    # create dataframe with the next set of molecules\n",
    "    tmp_df = df.iloc[query_idx].copy()\n",
    "    # get the shape scores\n",
    "    shape_res = oracle.get_values(tmp_df.SMILES.values)\n",
    "    # add the results to the dataframe\n",
    "    tmp_df = compile_results(tmp_df, shape_res)\n",
    "    tmp_df['cycle'] = i+1\n",
    "    # add the current dataframe to result_list\n",
    "    result_list.append(tmp_df)\n",
    "    # keep track of the molecules we've used\n",
    "    used += list(tmp_df.index)\n",
    "    # update the optimizer with the new values\n",
    "    #optimizer.teach(query_desc, tmp_df.score.values)\n",
    "    optimizer.teach(np.stack(tmp_df.fp.values), tmp_df.score.values)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09128435",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Combine the results from the active active learning cycles into a one dataframe. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "80cac783",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "600"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "combo_df = pd.concat(result_list)\n",
    "len(combo_df)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dac141fb",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "View the score distribution for the active learning selections. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "f685443a",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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1iOPPGJ5crnmzp2r/xbfeOMN69dff7W++eYbq23btvouE1fyyZBWZsyYYcXGxlo1a9bUB339+vX2ZbfeeqsOYk8M6Ysp27p166yEhAQdgOqWg5deeknfcubpZSsvL7eef/55HcxBQUFWTEyM9fjjj1t//PGHZZKvvvpKf2icPdnKoh5V2c5+TatWrfRxUL8z9YFiogstm/r5XOt78u/MU0L6YsqmviwmJSVZwcHBOrDVrY7FxcWWp5dr+vTp+hZAVa6oqCgrJSXF+u2331y63wxVCQCAoXzumjQAAJ6CkAYAwFCENAAAhiKkAQAwFCENAIChCGkAAAxFSAMAYChCGgAAQxHSAAAYipAGAMBQhDQAp1PDngK4cIQ04MM++ugjPc62Goe6Xr16euxmNea2MmfOHGnevLkEBgbqoUttYyErOTk50rNnT6lTp44eirFPnz4OY1w///zz0qpVK3n77belcePGEhQUpOcXFBTocaIbNGigX6fGUf7+++/dUHLAMxDSgI/Kzc2VBx54QAYOHCjZ2dmyevVqueeee/RYubNmzZKhQ4fKkCFD9FjIS5culWuvvdY+jrcK6KNHj8qaNWv0WNa7d++W+++/3+H91Tjl//nPf2TRokV63GTlvvvuk/z8fPn8888lKytLWrduLV26dNHvBaASLh1zC4AxsrKy9FB9e/fu/dOy6Oho69lnn630dWpcbjV+tRqL3EaNI6zea+PGjfahGGvUqGHl5+fb1/n666+tkJAQq7S01OH91FCib775ZjWWDPAeAZUFNwDv17JlS12LVae7k5OT5Y477pB7771XysvL5eDBg3pZZVStOyYmRk82zZo1k7CwML2sXbt2et5VV12lT2vbqNPax48f16fVz1RSUiK//vqr08oJeDJCGvBRl112mT5VvW7dOvniiy9kxowZ8uyzz8rKlSur5f1r167t8FwFtLq2rU6rn00FPIA/I6QBH+bn5ycdOnTQ07hx43TtVwV3o0aNdFh36tTpT6+Jj4+X/fv368lWm/755591ozBVo66Kuv6cl5cnAQEB+v0B/HeENOCjNmzYoINYneaOiIjQz3///Xcdwqp19mOPPabnd+vWTY4dOybffvutDB8+XLcAV6fIU1JSZNq0aVJRUSGPP/643HrrrdK2bdsqt6del5iYKL169ZJJkybJddddp0+rf/rpp/KXv/zlnK8FfBUhDfgodQvU2rVrddAWFRXpWvRrr72mQ1kpLS2VqVOnylNPPSX169fX16ttte+PP/5YB/Ytt9wi/v7+0rVrV326/FzU6z777DN9Sn3AgAH6C0FkZKR+j4YNG7qkzICn8VOtx9y9EwAA4M+4TxoAAEMR0gAAGIqQBgDAUIQ0AACGIqQBADAUIQ0AgKEIaQAADEVIAwBgKEIaAABDEdIAABiKkAYAQMz0v5h4CoZhR4cKAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.displot(x=\"score\",data=combo_df);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76743058",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Run Random Selections to Compare With Active Learning\n",
    "Is active learning really better?  Let's select 600 random molecules and compare with the 600 selected using active learning. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "a04615f0",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "53266fb3036b4b18a77330adc58947ae",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/600 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2025-11-05 09:45:20.839\u001b[0m | \u001b[31m\u001b[1mERROR   \u001b[0m | \u001b[36mgen_conformers\u001b[0m:\u001b[36mgenerate_conformers\u001b[0m:\u001b[36m70\u001b[0m - \u001b[31m\u001b[1mFailed to generate 3D confs for Cc1ccccc1N1CCN(S(=O)(=O)C[C@@]23CC[C@H](C[C@H]2NC(=O)[C@@H]([NH3+])CCS(C)(=O)=O)C3(C)C)CC1\u001b[0m\n",
      "\u001b[32m2025-11-05 09:46:20.629\u001b[0m | \u001b[31m\u001b[1mERROR   \u001b[0m | \u001b[36mgen_conformers\u001b[0m:\u001b[36mgenerate_conformers\u001b[0m:\u001b[36m70\u001b[0m - \u001b[31m\u001b[1mFailed to generate 3D confs for C[C@H](O/N=C1/[C@H]2O[C@@H]2[C@@H](O)[C@H]2[C@H]1CCn1c(=O)n(-c3ccccc3)c(=O)n12)c1cn([C@H](CO)Cc2ccccc2)nn1\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "random_df = df.sample(600).copy()\n",
    "random_shape_res = oracle.get_values(random_df.SMILES.values)\n",
    "random_df = compile_results(random_df, random_shape_res)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "327b63d1",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "View the score distribution for the random selection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "54bc2f6c",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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7iwBAQESFxcnX3zxhburBABAkzA+qP/973/LlClTJDk5Wb766ivp2bOnJCYmyoEDB9xdNQAATjrjg3rGjBlyxx13yG233Sbdu3eXefPmScuWLWXRokXurhoAAPZelKOiokIyMjIkKSnJsa9Zs2aSkJAg6enpdb6mvLxcbzWKior01+Li4kbX59ChQ/rrbz9nS1V5qdPlFOf+/P9127dD/Hx9KIf24feHvwveN0x5P8zLcbzfuyI3lDZt2oiPj/N1Estg+/bts1QVP//881r777//fuvCCy+s8zXJycn6NWy0Ab8D/A7wO8DvgBjQBkVFRY3KQqN71M5QvW91TrtGdXW1/Pbbb9KuXbsGfaJRn6QiIyNl7969EhQUJHZGW9AO/D7wd8F7hPPvlapH3RhGB3VoaKg0b95c8vPza+1Xj8PDw+t8jb+/v96O1bZtW6froBrb7kFdg7agHfh94O+C94imf680ejJZixYtpHfv3pKWllarh6wex8fHu7VuAAA0BaN71Ioaxh49erScf/75cuGFF8qsWbPk8OHDehY4AADezvigvuGGG+TXX3+VRx99VPLy8qRXr16ydu1aCQsLO6n/rho+V9duHz+Mbke0Be3A7wN/F7xHuO+90kfNKHNpiQAAwB7nqAEAsDuCGgAAgxHUAAAYjKAGAMBgtg5qZ5fPXLZsmb7L2ZAhQ8SO7VBYWCjjx4+XiIgIPbuxa9eu8v7774sd20JdLtitWzcJDAzUdySaPHmylJWViSfbtGmTDBo0SDp27Kh/z1etWvU/X7NhwwY577zz9O/DmWeeKUuWLBFP19B2WLFihVx++eXSvn17fbMLda+HdevWiadz5vehxmeffSa+vr76ah1vsMmJtlBrTzz88MPSqVMn/feh3l8auqiUbYPa2eUz9+zZI/fdd5/85S9/ETu2g1ooRb0ZqXZ46623JDs7WxYsWCCnnnqq2K0tli5dKg899JB+fmZmpixcuFCX8Y9//EM8mbpPgfrZ1YeWE7F79265+uqr5dJLL5VvvvlGJk2aJLfffrvHh1RD20G9iau/DfWhVS0mpNpDval//fXXYqd2OPYD/S233CKXXXaZeIvDTrTF8OHD9U261PuDer9844039If7BrFsSi3qMX78eMfjo0ePWh07drRSU1PrfU1VVZXVt29f6+WXX7ZGjx5tDR482LJbO8yd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",
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.displot(x=\"score\",data=random_df);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2cfc437b",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Compare the scores for random selections with active learning. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "054caae0",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "active_top_100_df = combo_df.sort_values(\"score\",ascending=False).head(100)\n",
    "active_top_100_df['dataset'] = \"active learning\"\n",
    "random_top_100_df = random_df.sort_values(\"score\",ascending=False).head(100)\n",
    "random_top_100_df['dataset'] = \"random\"\n",
    "plot_df = pd.concat([active_top_100_df, random_top_100_df])\n",
    "sns.boxplot(x=\"dataset\",y=\"score\",data=plot_df);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d68ce763",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Plot the scores of the molecules selected in each active learning round.  Remember that the first active learning cycle was randomly selected. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "9366f78c",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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N28u/fr1k1dffdUsUAogMFhbCnCYRYsWyaRJk8yjLnTXsmXLSr2fLn7pxgUw8/LyJCws7IrnXXXVVWarahrsdN2es2fPyqxZs+QHP/iB1KxZU9555x357W9/K3369AnqFjQgkGi5ARy20vnKlSvlnnvuMS03/hYAff31180Hp7YMNG7cWH7605/6Fr788ssvZfLkyaYVRbei3VLagqPHP/vss0LvOXfuXGnbtq1vf8+ePWaFaw0Fuqjr7bffLqdOnarw95Wbm2taUKKioszqzt26dTOtPV66qJ8u7qfP161bV77//e/LihUrCr2Hfn8TJ06U+++/33zfAwYM8LUYactMly5dzGt79Ogh6enpJXZL6WKgQ4YMkaeeekpatGhhVprWldEvXrzoO0cXv9T7r6GwdevWZoVvf61iBT300ENy6NAh+fe//20Wb+3YsaO0a9dOxo8fb1ar13v52GOP+V3VWq/vkUce8e0vXrxYrr/+egkPDzfXqN93STIzM2XYsGHm77hRo0Zy6623musA3IxwAzhIWlqa6dJo3769jBo1ynzIFezOWLt2rQkzAwcOlA8//NB8qHft2tU8p10frVq1Mh+g+uGsW1H6Yash4MUXXyx0XPdHjBjha4HQVoZOnTqZldd11frjx4+bD9CK0g9n7W57+eWX5aOPPpKf//zn8l//9V+yb98+8/y3334rnTt3Nt+fBqtf/vKXJlBt27at0Pu88MILprXmvffek4ULF/qOa1fQ008/ba5XW0vGjRtX6vW8/fbb8sUXX5hHfU8NgAWDpK7ura1mGp7++te/yvPPP29W/S5Jfn6++d5Gjhzpt6VNg433uvbu3SsffPCB7zn9e9R7MnbsWN8q7Rq29B58/PHH8tprr8k111zj98/VQKYhr379+vLPf/7T3Bf9s/TeassW4FoeAI7Ro0cPz7x588zXFy9e9DRu3Njz9ttv+57v3r27Z+TIkSW+/uqrr/bMnTu30LElS5Z4IiIifPv6fNu2bX376enpmp48e/fuNfszZ8709O/fv9B7ZGZmmnP0XH/0GvX506dPF3vuyy+/9NSoUcNz5MiRQsf79u3rSUlJKfF7GTRokOeBBx7w7f/4xz/2dOrUye+f++abb/qOrV271hy7cOGC2Z8+fbonPj7e9/yYMWPMfbp06ZLv2M9//nNPUlKS+Vrvg77+gw8+8D2/b98+c6zovfU6fvy4eX7OnDmeK0lMTPTcc889vv1JkyZ5EhISfPstW7b0TJ06tcTX65+zevVq8/Vf/vIXT/v27T35+fm+53Nzcz116tTxbNiw4YrXAjgVLTeAQ2hXirZUaPeM0t/0tRhYa2+8tHujb9++lfpzfvGLX5hui3/961++VpubbrrJtBip3bt3mxYNb62Kbt7ntLWjvLT14fLly6bVqOB7ai2K9/30+ZkzZ5ruKO1a0ec3bNggGRkZhd5LW3f8ueGGG3xfazeOKq2lRbt8tGi74Gu85+vfg957vSde2nLSsGHDEt+vPMXC2k2lXW7aWqWtK9rl5W1p0mvQFqOy/h3r39X+/ftNy433vur90/euyN8V4BQUFAMOoSHm0qVLhbo19ENT6y4WLFggERERASkM1hE82u2kH6o//OEPzaPW+BSs+xk8eLD8/ve/L/Zab3AoD30/DRI7duwoFCiUt9D3ySeflPnz55uaFg04WpejtTVFu1b0uD+1atXyfe2tNdKuopIUPN/7mtLOv5ImTZqYmpeitUz+6L3Vv9PVq1ebLjbtWrrtttvMc+X9+9V7q4GvaDej95oAt6LlBnAADTXLli0zdSPaOuPd9DdzDTve4lptoShtWLN+WGoryJVobYgWLmsdzIEDB0xrjpe2WHzyySemgFZbLApuJYWL0mjtjl6TtkoUfT8NWkprRbQQVuuM4uPjpU2bNlU+fL0kWu+kfx9aC+OlrSOnT58u8TWhoaHmHmrI0JYXfyFE31Npq5AWHC9ZssRs+jpvqNEWGL3vZR26rn9XWrfUtGnTYvdWwzDgVoQbwAH+/ve/mw/PO++804ymKbj97Gc/83VNTZ8+3QQdfdTCVO3yKdjCoh+MW7ZskSNHjpQ6umno0KGSnZ1tWmx69+5dqLVIi1m/+eYb0z2mha/avaFdRFrweqXgpNdTNJxpd5SGKS3S1aLngwcPmu632bNnmwJide2118rGjRvl/fffN9/Xr371K1PEbAXtgtO5abSgV69TQ45+rQHE2yrkz+OPPy7R0dFmJJgG1U8//dQEDy0K14CnAcfrrrvukrfeessUaxctftbRXRpyn3nmGfP6nTt3yh//+Ee/f6beVx05psFQC4r13moR9L333iuHDx8O4F0B7IVwAziAhhf9QPX327aGGx0FpCNqdDj0K6+8YkbQ6PBh7V4qOKJIR0ppPY0O6y6tW0JbCLR7RMOHfkAWpEFHW1I0yPTv3990E2kXkXa7aAtFaX70ox+ZD3Lv5q2R0RYKDTcPPPCAaRnRodganGJiYszzDz/8sGmF0JE/+j1qi46eYxUNJzoEXr8fHZ2mdTJ6z3T4fUm01kXrmLT1See50e+/V69eJoxqt1vBv1sNczpkXYOUhqGCtFVHu+eeffZZUxv03//9375RZUXp0HcNs3ofNbB26NDBBGStuWnQoEEA7whgLyFaVWz1RQCAk2kriLbKvPnmm5Uu6Fb637IGnF//+teSnJwckGsEggkFxQBQTtplpN1I2mql8wXpDMPa5actOZV18uRJMyfOsWPHfHPbACgfwg0AlJOOYNIZh7XYWrujtAtJi4WLjrKqCC3+1ToZnRiwtOHlAEpGtxQAAHAVCooBAICrEG4AAICrEG4AAICrEG4AAICrEG4AAICrEG4AAICrEG4AAICrEG4AAIC4yf8BOgCcvuBHt/0AAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ax = sns.boxplot(x=\"cycle\", y=\"score\", data=combo_df,color=\"lightblue\")\n",
    "ax.set_xlabel(\"Active Learning Cycle\");"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51530f64",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Let's look at the highest scoring overlay and make sure our results make sense. We'll use [Py3DMol](https://pypi.org/project/py3Dmol/) to do this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "ae8cd85b",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "application/3dmoljs_load.v0": "<div id=\"3dmolviewer_1762364815907819\"  style=\"position: relative; width: 640px; height: 480px;\">\n        <p id=\"3dmolwarning_1762364815907819\" style=\"background-color:#ffcccc;color:black\">3Dmol.js failed to load for some reason.  Please check your browser console for error messages.<br></p>\n        </div>\n<script>\n\nvar loadScriptAsync = function(uri){\n  return new Promise((resolve, reject) => {\n    //this is to ignore the existence of requirejs amd\n    var savedexports, savedmodule;\n    if (typeof exports !== 'undefined') savedexports = exports;\n    else exports = {}\n    if (typeof module !== 'undefined') savedmodule = module;\n    else module = {}\n\n    var tag = document.createElement('script');\n    tag.src = uri;\n    tag.async = true;\n    tag.onload = () => {\n        exports = savedexports;\n        module = savedmodule;\n        resolve();\n    };\n  var firstScriptTag = document.getElementsByTagName('script')[0];\n  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\n});\n};\n\nif(typeof $3Dmolpromise === 'undefined') {\n$3Dmolpromise = null;\n  $3Dmolpromise = loadScriptAsync('https://cdn.jsdelivr.net/npm/3dmol@2.5.3/build/3Dmol-min.js');\n}\n\nvar viewer_1762364815907819 = null;\nvar warn = document.getElementById(\"3dmolwarning_1762364815907819\");\nif(warn) {\n    warn.parentNode.removeChild(warn);\n}\n$3Dmolpromise.then(function() {\nviewer_1762364815907819 = $3Dmol.createViewer(document.getElementById(\"3dmolviewer_1762364815907819\"),{backgroundColor:\"white\"});\nviewer_1762364815907819.zoomTo();\n\tviewer_1762364815907819.addModel(\"2CHW_ligand2\\n     RDKit          3D\\n\\n 31 35  0  0  1  0  0  0  0  0999 V2000\\n   50.8990   16.3190   31.0490 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.8180   16.4300   31.9910 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.0900   17.5720   31.8950 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4830   18.6530   31.1140 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.6960   19.8030   31.0690 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.5060   19.8780   31.8010 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.1210   18.7960   32.5900 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.9120   17.6500   32.6170 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.4980   16.5900   33.4170 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.0760   16.4810   34.6750 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.9180   17.3100   34.9960 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.6950   15.4550   35.5310 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.2370   15.2870   36.8230 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4490   16.3440   37.5170 Cl  0  0  0  0  0  0  0  0  0  0  0  0\\n   47.7970   14.2260   37.6120 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.8480   13.3370   37.1520 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.3170   13.5250   35.8880 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.7300   14.5650   35.0630 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.1850   14.6820   33.8300 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.5280   15.6630   32.9870 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   45.9320   15.7890   31.5640 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   44.6330   14.5990   31.0330 S   0  0  0  0  0  0  0  0  0  0  0  0\\n   45.2080   13.0480   30.3300 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.5170   12.6520   30.2720 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.6430   13.2240   30.6340 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.6300   12.3630   30.3220 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.1340   11.2520   29.7580 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.8160   11.3990   29.7150 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   45.8470   10.5960   29.2640 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   44.5940   11.0010   29.3190 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   44.2880   12.1810   29.8280 N   0  0  0  0  0  0  0  0  0  0  0  0\\n  1  2  1  0\\n  2  3  1  0\\n  3  4  2  0\\n  3  8  1  0\\n  4  5  1  0\\n  5  6  2  0\\n  6  7  1  0\\n  7  8  2  0\\n  8  9  1  0\\n  9 10  1  0\\n  9 20  1  0\\n 10 11  2  0\\n 10 12  1  0\\n 12 13  2  0\\n 12 18  1  0\\n 13 14  1  0\\n 13 15  1  0\\n 15 16  2  0\\n 16 17  1  0\\n 17 18  2  0\\n 18 19  1  0\\n 19 20  2  0\\n 20 21  1  0\\n 21 22  1  0\\n 22 23  1  0\\n 23 24  2  0\\n 23 31  1  0\\n 24 25  1  0\\n 24 28  1  0\\n 25 26  2  0\\n 26 27  1  0\\n 27 28  1  0\\n 28 29  2  0\\n 29 30  1  0\\n 30 31  2  0\\nM  END\\n\",\"mol\");\n\tviewer_1762364815907819.addModel(\"\\n     RDKit          3D\\n\\n 18 19  0  0  0  0  0  0  0  0999 V2000\\n   46.3021   15.7457   33.0218 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.3746   16.5719   33.4411 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.9948   16.3924   34.6919 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.9204   17.2214   35.0227 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.6817   15.3465   35.6525 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.2756   15.1545   36.9222 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.8767   14.1425   37.6639 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.8857   13.2515   37.2366 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.5539   14.0376   35.5825 S   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.8466   17.6428   32.6235 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.1415   18.8319   32.5245 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.5308   19.9016   31.7641 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.7113   19.7857   31.0439 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4369   18.6415   31.1097 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.0178   17.5711   31.8896 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.8143   16.3673   31.9249 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4945   15.3892   32.6066 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   50.9743   16.3178   31.1602 O   0  0  0  0  0  1  0  0  0  0  0  0\\n  1  2  1  0\\n  2  3  1  0\\n  3  4  2  0\\n  3  5  1  0\\n  5  6  2  0\\n  6  7  1  0\\n  7  8  2  0\\n  8  9  1  0\\n  2 10  1  0\\n 10 11  2  0\\n 11 12  1  0\\n 12 13  2  0\\n 13 14  1  0\\n 14 15  2  0\\n 15 16  1  0\\n 16 17  2  0\\n 16 18  1  0\\n  9  5  1  0\\n 15 10  1  0\\nM  CHG  1  18  -1\\nM  END\\n\",\"mol\");\n\tviewer_1762364815907819.setStyle({\"model\": 0},{\"stick\": {\"colorscheme\": \"greenCarbon\"}});\n\tviewer_1762364815907819.setStyle({\"model\": 1},{\"stick\": {\"colorscheme\": \"lightgreyCarbon\"}});\n\tviewer_1762364815907819.zoomTo();\nviewer_1762364815907819.render();\n});\n</script>",
      "text/html": [
       "<div id=\"3dmolviewer_1762364815907819\"  style=\"position: relative; width: 640px; height: 480px;\">\n",
       "        <p id=\"3dmolwarning_1762364815907819\" style=\"background-color:#ffcccc;color:black\">3Dmol.js failed to load for some reason.  Please check your browser console for error messages.<br></p>\n",
       "        </div>\n",
       "<script>\n",
       "\n",
       "var loadScriptAsync = function(uri){\n",
       "  return new Promise((resolve, reject) => {\n",
       "    //this is to ignore the existence of requirejs amd\n",
       "    var savedexports, savedmodule;\n",
       "    if (typeof exports !== 'undefined') savedexports = exports;\n",
       "    else exports = {}\n",
       "    if (typeof module !== 'undefined') savedmodule = module;\n",
       "    else module = {}\n",
       "\n",
       "    var tag = document.createElement('script');\n",
       "    tag.src = uri;\n",
       "    tag.async = true;\n",
       "    tag.onload = () => {\n",
       "        exports = savedexports;\n",
       "        module = savedmodule;\n",
       "        resolve();\n",
       "    };\n",
       "  var firstScriptTag = document.getElementsByTagName('script')[0];\n",
       "  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\n",
       "});\n",
       "};\n",
       "\n",
       "if(typeof $3Dmolpromise === 'undefined') {\n",
       "$3Dmolpromise = null;\n",
       "  $3Dmolpromise = loadScriptAsync('https://cdn.jsdelivr.net/npm/3dmol@2.5.3/build/3Dmol-min.js');\n",
       "}\n",
       "\n",
       "var viewer_1762364815907819 = null;\n",
       "var warn = document.getElementById(\"3dmolwarning_1762364815907819\");\n",
       "if(warn) {\n",
       "    warn.parentNode.removeChild(warn);\n",
       "}\n",
       "$3Dmolpromise.then(function() {\n",
       "viewer_1762364815907819 = $3Dmol.createViewer(document.getElementById(\"3dmolviewer_1762364815907819\"),{backgroundColor:\"white\"});\n",
       "viewer_1762364815907819.zoomTo();\n",
       "\tviewer_1762364815907819.addModel(\"2CHW_ligand2\\n     RDKit          3D\\n\\n 31 35  0  0  1  0  0  0  0  0999 V2000\\n   50.8990   16.3190   31.0490 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.8180   16.4300   31.9910 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.0900   17.5720   31.8950 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4830   18.6530   31.1140 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.6960   19.8030   31.0690 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.5060   19.8780   31.8010 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.1210   18.7960   32.5900 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.9120   17.6500   32.6170 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.4980   16.5900   33.4170 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.0760   16.4810   34.6750 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.9180   17.3100   34.9960 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.6950   15.4550   35.5310 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.2370   15.2870   36.8230 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4490   16.3440   37.5170 Cl  0  0  0  0  0  0  0  0  0  0  0  0\\n   47.7970   14.2260   37.6120 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.8480   13.3370   37.1520 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.3170   13.5250   35.8880 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.7300   14.5650   35.0630 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.1850   14.6820   33.8300 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.5280   15.6630   32.9870 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   45.9320   15.7890   31.5640 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   44.6330   14.5990   31.0330 S   0  0  0  0  0  0  0  0  0  0  0  0\\n   45.2080   13.0480   30.3300 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.5170   12.6520   30.2720 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.6430   13.2240   30.6340 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.6300   12.3630   30.3220 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.1340   11.2520   29.7580 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.8160   11.3990   29.7150 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   45.8470   10.5960   29.2640 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   44.5940   11.0010   29.3190 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   44.2880   12.1810   29.8280 N   0  0  0  0  0  0  0  0  0  0  0  0\\n  1  2  1  0\\n  2  3  1  0\\n  3  4  2  0\\n  3  8  1  0\\n  4  5  1  0\\n  5  6  2  0\\n  6  7  1  0\\n  7  8  2  0\\n  8  9  1  0\\n  9 10  1  0\\n  9 20  1  0\\n 10 11  2  0\\n 10 12  1  0\\n 12 13  2  0\\n 12 18  1  0\\n 13 14  1  0\\n 13 15  1  0\\n 15 16  2  0\\n 16 17  1  0\\n 17 18  2  0\\n 18 19  1  0\\n 19 20  2  0\\n 20 21  1  0\\n 21 22  1  0\\n 22 23  1  0\\n 23 24  2  0\\n 23 31  1  0\\n 24 25  1  0\\n 24 28  1  0\\n 25 26  2  0\\n 26 27  1  0\\n 27 28  1  0\\n 28 29  2  0\\n 29 30  1  0\\n 30 31  2  0\\nM  END\\n\",\"mol\");\n",
       "\tviewer_1762364815907819.addModel(\"\\n     RDKit          3D\\n\\n 18 19  0  0  0  0  0  0  0  0999 V2000\\n   46.3021   15.7457   33.0218 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.3746   16.5719   33.4411 N   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.9948   16.3924   34.6919 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.9204   17.2214   35.0227 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.6817   15.3465   35.6525 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.2756   15.1545   36.9222 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.8767   14.1425   37.6639 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.8857   13.2515   37.2366 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   46.5539   14.0376   35.5825 S   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.8466   17.6428   32.6235 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.1415   18.8319   32.5245 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   47.5308   19.9016   31.7641 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   48.7113   19.7857   31.0439 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4369   18.6415   31.1097 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.0178   17.5711   31.8896 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.8143   16.3673   31.9249 C   0  0  0  0  0  0  0  0  0  0  0  0\\n   49.4945   15.3892   32.6066 O   0  0  0  0  0  0  0  0  0  0  0  0\\n   50.9743   16.3178   31.1602 O   0  0  0  0  0  1  0  0  0  0  0  0\\n  1  2  1  0\\n  2  3  1  0\\n  3  4  2  0\\n  3  5  1  0\\n  5  6  2  0\\n  6  7  1  0\\n  7  8  2  0\\n  8  9  1  0\\n  2 10  1  0\\n 10 11  2  0\\n 11 12  1  0\\n 12 13  2  0\\n 13 14  1  0\\n 14 15  2  0\\n 15 16  1  0\\n 16 17  2  0\\n 16 18  1  0\\n  9  5  1  0\\n 15 10  1  0\\nM  CHG  1  18  -1\\nM  END\\n\",\"mol\");\n",
       "\tviewer_1762364815907819.setStyle({\"model\": 0},{\"stick\": {\"colorscheme\": \"greenCarbon\"}});\n",
       "\tviewer_1762364815907819.setStyle({\"model\": 1},{\"stick\": {\"colorscheme\": \"lightgreyCarbon\"}});\n",
       "\tviewer_1762364815907819.zoomTo();\n",
       "viewer_1762364815907819.render();\n",
       "});\n",
       "</script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# read the the query molecule\n",
    "query_mol = Chem.MolFromMolFile(\"data/2chw_lig.sdf\")\n",
    "# get the highest scoring molecule from combo_df\n",
    "db_mol = combo_df.sort_values(\"score\",ascending=False).shape_res.values[0].best_mol\n",
    "db_mol = Chem.RemoveHs(db_mol)\n",
    "# For Py3DMol, we need to convert molecules to molblocks\n",
    "query_mblock = Chem.MolToMolBlock(query_mol)\n",
    "db_mblock = Chem.MolToMolBlock(db_mol)\n",
    "# create a Py3DMol view\n",
    "view = py3Dmol.view()\n",
    "# add the molecules\n",
    "view.addModel(query_mblock, 'mol')\n",
    "view.addModel(db_mblock, 'mol')\n",
    "# color the molecules\n",
    "view.setStyle({'model': 0},{'stick':{'colorscheme':'greenCarbon'}})\n",
    "view.setStyle({'model': 1},{'stick':{'colorscheme':'lightgreyCarbon'}})\n",
    "# Zoom in and show the molecules\n",
    "view.zoomTo()\n",
    "view.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "695f830f",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "917dd9c5",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
